package com.fsnbigdata.service.impl;

import com.fsnbigdata.domain.*;
import com.fsnbigdata.domain.dto.NamingPair;
import com.fsnbigdata.service.api.ProductService;
import com.fsnbigdata.util.ObjectNull;
import com.querydsl.core.types.Predicate;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.roo.addon.layers.service.annotations.RooServiceImpl;
import com.fsnbigdata.repository.ProductRepository;
import com.fsnbigdata.service.api.ProductEnterpriseService;
import com.fsnbigdata.service.api.ProductImageService;
import com.fsnbigdata.service.api.ProductOrganismService;
import io.springlets.data.domain.GlobalSearch;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Root;

/**
 * = ProductServiceImpl
 * <p>
 * TODO Auto-generated class documentation
 */
@RooServiceImpl(service = ProductService.class)
@Service
@Transactional(readOnly = true)
public class ProductServiceImpl implements ProductService {
    
    /**
     * TODO Auto-generated attribute documentation
     */
    private ProductRepository productRepository;
    
    /**
     * TODO Auto-generated attribute documentation
     */
    private ProductEnterpriseService productEnterpriseService;
    
    /**
     * TODO Auto-generated attribute documentation
     */
    private ProductOrganismService productOrganismService;
    
    /**
     * TODO Auto-generated attribute documentation
     */
    private ProductImageService productImageService;
    
    /**
     * TODO Auto-generated constructor documentation
     *
     * @param productRepository
     * @param productEnterpriseService
     * @param productImageService
     * @param productOrganismService
     */
    @Autowired
    public ProductServiceImpl(ProductRepository productRepository, @Lazy ProductEnterpriseService productEnterpriseService, @Lazy ProductImageService productImageService, @Lazy ProductOrganismService productOrganismService) {
        setProductRepository(productRepository);
        setProductEnterpriseService(productEnterpriseService);
        setProductImageService(productImageService);
        setProductOrganismService(productOrganismService);
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @return ProductRepository
     */
    public ProductRepository getProductRepository() {
        return productRepository;
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @param productRepository
     */
    public void setProductRepository(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @return ProductEnterpriseService
     */
    public ProductEnterpriseService getProductEnterpriseService() {
        return productEnterpriseService;
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @param productEnterpriseService
     */
    public void setProductEnterpriseService(ProductEnterpriseService productEnterpriseService) {
        this.productEnterpriseService = productEnterpriseService;
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @return ProductImageService
     */
    public ProductImageService getProductImageService() {
        return productImageService;
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @param productImageService
     */
    public void setProductImageService(ProductImageService productImageService) {
        this.productImageService = productImageService;
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @return ProductOrganismService
     */
    public ProductOrganismService getProductOrganismService() {
        return productOrganismService;
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @param productOrganismService
     */
    public void setProductOrganismService(ProductOrganismService productOrganismService) {
        this.productOrganismService = productOrganismService;
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @param product
     * @param enterprisesToAdd
     * @return Product
     */
    @Transactional
    public Product addToEnterprises(Product product, Iterable<ProductEnterprise> enterprisesToAdd) {
        product.addToEnterprises(enterprisesToAdd);
        return getProductRepository().save(product);
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @param product
     * @param imagesToAdd
     * @return Product
     */
    @Transactional
    public Product addToImages(Product product, Iterable<ProductImage> imagesToAdd) {
        product.addToImages(imagesToAdd);
        return getProductRepository().save(product);
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @param product
     * @param organismsToAdd
     * @return Product
     */
    @Transactional
    public Product addToOrganisms(Product product, Iterable<ProductOrganism> organismsToAdd) {
        product.addToOrganisms(organismsToAdd);
        return getProductRepository().save(product);
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @param product
     * @param enterprisesToRemove
     * @return Product
     */
    @Transactional
    public Product removeFromEnterprises(Product product, Iterable<Long> enterprisesToRemove) {
        List<ProductEnterprise> enterprises = getProductEnterpriseService().findAll(enterprisesToRemove);
        product.removeFromEnterprises(enterprises);
        return getProductRepository().save(product);
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @param product
     * @param imagesToRemove
     * @return Product
     */
    @Transactional
    public Product removeFromImages(Product product, Iterable<Long> imagesToRemove) {
        List<ProductImage> images = getProductImageService().findAll(imagesToRemove);
        product.removeFromImages(images);
        return getProductRepository().save(product);
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @param product
     * @param organismsToRemove
     * @return Product
     */
    @Transactional
    public Product removeFromOrganisms(Product product, Iterable<Long> organismsToRemove) {
        List<ProductOrganism> organisms = getProductOrganismService().findAll(organismsToRemove);
        product.removeFromOrganisms(organisms);
        return getProductRepository().save(product);
    }
    
    @Override
    public List<NamingPair> findAllByInitial(String initial) {
        return getProductRepository().findAllByInitial(initial);
    }
    
    public List<Product> findAllByType(Integer type) {
        return getProductRepository().findAllByType(type);
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @param product
     */
    @Transactional
    public void delete(Product product) {
        // Clear bidirectional one-to-many parent relationship with ProductEnterprise
        for (ProductEnterprise item : product.getEnterprises()) {
            item.setProduct(null);
        }
        // Clear bidirectional one-to-many parent relationship with ProductImage
        for (ProductImage item : product.getImages()) {
            item.setProduct(null);
        }
        // Clear bidirectional one-to-many parent relationship with ProductOrganism
        for (ProductOrganism item : product.getOrganisms()) {
            item.setProduct(null);
        }
        getProductRepository().delete(product);
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @param entities
     * @return List
     */
    @Transactional
    public List<Product> save(Iterable<Product> entities) {
        return getProductRepository().save(entities);
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @param ids
     */
    @Transactional
    public void delete(Iterable<Long> ids) {
        List<Product> toDelete = getProductRepository().findAll(ids);
        getProductRepository().deleteInBatch(toDelete);
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @param entity
     * @return Product
     */
    @Transactional
    public Product save(Product entity) {
        return getProductRepository().save(entity);
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @param id
     * @return Product
     */
    public Product findOne(Long id) {
        return getProductRepository().findOne(id);
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @param id
     * @return Product
     */
    public Product findOneForUpdate(Long id) {
        return getProductRepository().findOneDetached(id);
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @param ids
     * @return List
     */
    public List<Product> findAll(Iterable<Long> ids) {
        return getProductRepository().findAll(ids);
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @return List
     */
    public List<Product> findAll() {
        return getProductRepository().findAll();
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @return Long
     */
    public long count() {
        return getProductRepository().count();
    }
    
    @Override
    public Page<Product> search(Predicate predicate, Pageable pageable) {
        return getProductRepository().findAll(predicate, pageable);
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @param globalSearch
     * @param pageable
     * @return Page
     */
    public Page<Product> findAll(GlobalSearch globalSearch, Pageable pageable) {
        return getProductRepository().findAll(globalSearch, pageable, null);
    }
    
    @Override
    public Page<Product> findAll(GlobalSearch globalSearch, Pageable pageable, String creator) {
        return getProductRepository().findAll(globalSearch, pageable, creator);
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @param ids
     * @param globalSearch
     * @param pageable
     * @return Page
     */
    public Page<Product> findAllByIdsIn(List<Long> ids, GlobalSearch globalSearch, Pageable pageable) {
        return getProductRepository().findAllByIdsIn(ids, globalSearch, pageable);
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @return Class
     */
    public Class<Product> getEntityType() {
        return Product.class;
    }
    
    /**
     * TODO Auto-generated method documentation
     *
     * @return Class
     */
    public Class<Long> getIdType() {
        return Long.class;
    }
    
    /**
     * 通过类型查询所有数据
     * @return
     */
    @Override
    public List<List<Product>> findAllByType() {
            List<List<Product>> list = new ArrayList<>();
            List<Product> products1 = getProductRepository().findAllByCategoryLike("食品");
            List<Product> products2 = getProductRepository().findAllByCategoryLike("药品");
            List<Product> products3 = getProductRepository().findAllByCategoryLike("保健品");
            List<Product> products4 = getProductRepository().findAllByCategoryLike("其他");
            if (products1 != null && products1.size() > 4) {
                list.add(products1.subList(0, 4));
            } else {
                list.add(products1);
            }
            if (products2 != null && products2.size() > 4) {
                list.add(products2.subList(0, 4));
            } else {
                list.add(products2);
            }
            if (products3 != null && products3.size() > 4) {
                list.add(products3.subList(0, 4));
            } else {
                list.add(products3);
            }

            if (products4 != null && products4.size() > 4) {
                list.add(products4.subList(0, 4));
            } else {
                list.add(products4);
            }
        return list;
    }

    @Override
    public List findByPageAndSize(String type,String brand,String category,String barCode,String enterpriseName,String organismName, String name, Pageable pageable) {

        class NewProduct{
            private String id;
            private String initial;
            private String brand;
            private String name;
            private String url;
            private String isPort;
            private String specification;
            private String type;


            public String getId() {
                return id;
            }

            public void setId(String id) {
                this.id = id;
            }

            public String getInitial() {
                return initial;
            }

            public void setInitial(String initial) {
                this.initial = initial;
            }

            public String getName() {
                return name;
            }

            public void setName(String name) {
                this.name = name;
            }

            public String getUrl() {
                return url;
            }

            public void setUrl(String url) {
                this.url = url;
            }


            public String getBrand() {
                return brand;
            }

            public void setBrand(String brand) {
                this.brand = brand;
            }

            public String getIsPort() {
                return isPort;
            }

            public void setIsPort(String isPort) {
                this.isPort = isPort;
            }

            public String getSpecification() {
                return specification;
            }

            public void setSpecification(String specification) {
                this.specification = specification;
            }

            public String getType() {
                return type;
            }

            public void setType(String type) {
                this.type = type;
            }
        }
        List<Long> ids = new ArrayList<>();
        //根据企业家获取产品Id
        if (enterpriseName!=null&&!"".equals(enterpriseName)){
            ids = productEnterpriseService.getIdsByName(enterpriseName);
        }
        //根据产品物种Id获取企业Id
        List<Long> ids1 = new ArrayList<>();
        if (organismName!=null&&!"".equals(organismName)){
            ids1 = productOrganismService.getIdsByName(organismName);
        }

        String sign = ids.size()>0?ids.get(0)+"":null;
        ids = ids.size()>0?ids:null;

        String sign1 = ids1.size()>0?ids1.get(0)+"":null;
        ids1 = ids1.size()>0?ids1:null;
        List list = new ArrayList();

        List<NewProduct> newProducts =new ArrayList<>();
        List<Object> productList = productRepository.findAllByIdsAndTypeAndName(type,brand,category,barCode,name,sign,sign1,ids,ids1,pageable);

        for (Object object:productList){
            Object[] obj = (Object[]) object;
            NewProduct newProduct = new NewProduct();
            newProduct.setId(""+obj[0]);
            newProduct.setName(ObjectNull.takeOutNull(obj[1]));
            newProduct.setBrand(ObjectNull.takeOutNull(obj[2]));
            newProduct.setInitial(ObjectNull.takeOutNull(obj[3]));
            newProduct.setIsPort(ObjectNull.takeOutNull(obj[4]));
            newProduct.setSpecification( ObjectNull.takeOutNull(obj[5]));
            newProduct.setType(ObjectNull.takeOutNull(obj[6]));

            if (productImageService.getUrl(Long.parseLong(newProduct.getId())).size()>0){
                newProduct.setUrl(productImageService.getUrl(Long.parseLong(newProduct.getId())).get(0));
            }

            newProducts.add(newProduct);
        }

        list.add(productRepository.CountByKey(type,brand,category,barCode,name,sign,sign1,ids,ids1));
        list.add(newProducts);
       return list;
    }
}
